use std::fmt::{Display, Formatter};
use std::process::id;

pub fn to_err_msg(line: usize, msg: &str) -> String {
    format!("[line {}] Error: {}", line, msg)
}


#[derive(Debug, Clone)]
enum Op {
    Add,
    Sub,
    Mul,
    Div,
    BitRev, // ~是右结合的
    LeftBracket,
    RightBracket,
    Call(String, usize) // 函数调用可等价为一个最高优先级的右结合操作符
}

impl Display for Op {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Op::Add => write!(f, "+"),
            Op::Sub => write!(f, "-"),
            Op::Mul => write!(f, "*"),
            Op::Div => write!(f, "/"),
            Op::BitRev => write!(f, "~"),
            Op::Call(name, count) => write!(f, "{}([{}])", name, count),
            Op::LeftBracket | Op::RightBracket => write!(f, "")
        }
    }
}

impl Op {
    // 数值越小，优先级越高
    pub fn privilege_value(&self) -> i32 {
        match self {
            Self::Add| Self::Sub => 2,
            Self::Mul | Self::Div => 1,
            Self::Call(_, _) => 0,
            Self::BitRev => 0,
            Self::LeftBracket | Self::RightBracket => 0
        }
    }
    
    pub fn from_arithmetic_char(c: char) -> Option<Self> {
        match c {
            '+' => Some(Op::Add),
            '-' => Some(Op::Sub),
            '*' => Some(Op::Mul),
            '/' => Some(Op::Div),
            _ => None
        }
    }

    pub fn is_left_compose(&self) -> bool {
        match self {
            Self::Call(_, _) | Self::BitRev => false,
            _ => true
        }
    }

    pub fn is_right_compose(&self) -> bool {
        match self {
            Self::BitRev | Self::Call(_, _) => true,
            _ => false
        }
    }

    pub fn is_real_op(&self) -> bool {
        match self {
            Self::RightBracket | Self::LeftBracket => false,
            _ => true
        }
    }
}

struct RpnParser {
    source: String,
    current: usize,
    op_stack: Vec<Op>,
    out_list: Vec<String>
}

impl RpnParser {
    pub fn new(s: String) -> Self {
        Self {current: 0, source: s, op_stack: vec![], out_list: vec![]}
    }

    pub fn to_rpn(&mut self) -> Result<String, String> {
        while !self.is_at_end() {
            let c = self.advance();
            match c {
                '+' | '-' | '*' | '/' => {
                    let op = Op::from_arithmetic_char(c).unwrap();
                    self.handle_op(op);
                }
                ' ' | '\t' | '\r' | '\n' => {}
                '(' => self.op_stack.push(Op::LeftBracket),
                ')' => {
                    while !self.op_stack.is_empty() {
                        let mut should_pop = false;
                        match self.op_stack.last() {
                            None => { return Err(self.error()); }
                            Some(_) => {
                                should_pop = true;
                            }
                        }

                        if should_pop {
                            match self.op_stack.pop().unwrap() {
                                Op::LeftBracket => {},
                                op => self.out_list.push(format!("{}", op))
                            }
                        }
                    }
                }
                _ => {
                    if c.is_ascii_alphabetic() || c == '_' {
                        // 解析变量
                        let name = self.identifier(c);
                        // 这是个函数
                        if self.match_char('(') {
                            match self.parse_args() {
                                Ok(args) => {
                                    self.handle_op(Op::Call(name, args.len()));
                                    self.out_list.extend(args);
                                }
                                Err(_) => { return Err(self.error()); }
                            }
                        } else {
                            self.out_list.push(name);
                        }
                    } else if c.is_ascii_digit() {
                        // 解析数字
                        match self.number(c) {
                            Ok(n) => { self.out_list.push(n); }
                            Err(_) => { return Err(self.error()); }
                        }
                    } else {
                        return Err(self.error());
                    }
                }
            }
        }

        match self.op_stack.last() {
            Some(op) => {
                match op {
                    Op::LeftBracket | Op::RightBracket => Err(self.error()),
                    _ => {
                        while !self.op_stack.is_empty() {
                            self.out_list.push(format!("{}", self.op_stack.pop().unwrap()));
                        }
                        Ok(self.out_list.join(" " ))
                    }
                }
            },

            None => Ok(self.out_list.join(" " ))
        }
    }

    fn handle_op(&mut self, op: Op) {
        println!("handle op: {:?}", op);
        loop {
            let mut should_pop_stack = false;
            match self.op_stack.last() {
                None => break,
                Some(last_op) => {
                    if (last_op.is_left_compose() && op.privilege_value() >= last_op.privilege_value())
                        || (last_op.is_right_compose() && op.privilege_value() > last_op.privilege_value()) {
                        self.out_list.push(format!("{}", last_op));
                        should_pop_stack = true;
                    } else {
                        break;
                    }
                }
            }

            if should_pop_stack {
                println!("pop op {}", self.op_stack.pop().unwrap());
            } else {
                break;
            }
        }

        self.op_stack.push(op);
    }

    fn error(&self) -> String {
        let mut ret = String::new();
        let cursor = if self.current == 0 {
            0_usize
        } else {
            self.current - 1
        };

        ret.push_str(&self.source);

        if !self.source.ends_with('\n') {
            ret.push('\n');
        }

        for _ in 0..cursor {
            ret.push(' ');
        }

        let mark_count = self.source.len() - cursor;

        for _ in 0..mark_count {
            ret.push('^');
        }

        // println!("current = {}, mark", self.current);

        ret
    }

    fn advance(&mut self) -> char {
        let ret = self.source.chars().nth(self.current).unwrap();
        self.current += 1;
        return ret;
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn number(&mut self, first_char: char) -> Result<String, ()> {
        let mut number_str = String::new();
        number_str.push(first_char);
        while self.peek().is_ascii_digit() {
            number_str.push(self.advance());
        }

        if self.peek() == '.' {
            if self.peek_next().is_ascii_digit() {
                number_str.push(self.advance());

                while self.peek().is_ascii_digit() {
                    number_str.push(self.advance());
                }

                Ok(number_str)
            } else {
                Err(())
            }
        } else {
            Ok(number_str)
        }
    }

    fn identifier(&mut self, first_char: char) -> String {
        let mut s = String::new();
        s.push(first_char);
        while self.peek().is_ascii_alphanumeric() || self.peek() == '_' {
            s.push(self.advance());
        }

        s
    }

    fn peek(&self) -> char {
        if self.is_at_end() { '\0' }
        else { self.source.chars().nth(self.current).unwrap() }
    }

    fn peek_next(&self) -> char {
        if self.is_at_end() { '\0' }
        else { self.source.chars().nth(self.current + 1).unwrap() }
    }

    // 如果匹配，则指针移到下一个字符；否则不动
    fn match_char(&mut self, c: char) -> bool {
        if self.is_at_end() {
            false
        } else {
            if self.source.chars().nth(self.current).unwrap() == c {
                self.current += 1;
                true
            } else {
                false
            }
        }
    }
    fn parse_args(&mut self) -> Result<Vec<String>, ()> {
        let mut args = vec![];
        while self.peek() != ')' && !self.is_at_end() {
            let c = self.advance();
            if c.is_ascii_alphabetic() || c == '_' {
                let identifier = self.identifier(c);
                args.push(identifier);

                // 略过所有空白字符
                self.skip_whitespace();
                if self.peek() == ',' {
                    self.advance();
                    self.skip_whitespace();
                    if self.peek() == ')' {
                        return Err(());
                    }

                    self.skip_whitespace();
                }
            } else if c.is_ascii_digit() {
                match self.number(c) {
                    Ok(s) => {
                        args.push(s);
                        if self.peek() == ',' {
                            self.advance();
                            self.skip_whitespace();
                            println!("skip 2, peek = {}", self.peek());
                            if self.peek() == ')' {
                                return Err(());
                            }

                            self.skip_whitespace();
                        }
                    }
                    Err(_) => { return Err(()); }
                }
            } else {
                return Err(());
            }
        }

        if self.is_at_end() {
            Err(())
        } else {
            self.advance();
            Ok(args)
        }
    }

    fn skip_whitespace(&mut self) {
        while self.peek().is_whitespace() {
            self.advance();
        }
    }
}

#[cfg(test)]
mod test {
    use crate::util::RpnParser;

    #[test]
    fn basic_test() {
        let s = "a + b + cc(aa, bb)";

        println!("{}", s);

        let mut parser = RpnParser::new(s.to_string());

        match parser.to_rpn() {
            Ok(repr) => println!("{}", repr),
            Err(e) => eprintln!("err: {}", e)
        }
    }
}


